//----------------------------------------------
// Multithreading Server using pthread
// ------------------------
// Author : Woo-Hyun, Kim
// Date : Feb. 12, 2004
// Email : woorung@empal.com             
//----------------------------------------------
#include <iostream>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//----------------------------------------------
#ifdef _WIN32  // on Windows
#include <winsock2.h>
#else  // on Linux
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <sys/time.h> // for using struct timeval as the timeout parameter of select();
#include <signal.h>
#include <pthread.h> // for using pthread and mutex
#include <semaphore.h> // for using semaphore
#endif
//----------------------------------------------
// for half-close like shutdown() on Windows
#ifdef _WIN32
#define SHUT_RD SD_RECEIVE
#define SHUT_WR SD_SEND
#define SHUT_RDWR SD_BOTH
#endif
//-----------------------------------------------
#define WAIT_QUEUE 10
#define SRV_PORT "2020"
#define BUF_SIZE 1024
//-----------------------------------------------
using namespace std;
//-----------------------------------------------
void *clnt_proc(void *arg)
{
	int clnt_sock = (int) arg;
	char recv_buf[BUF_SIZE];

	int recv_len=recv(clnt_sock,recv_buf,BUF_SIZE,0);
	if(recv_len==0) { // in case of EOF, that is, a client socket have closed.
		close(clnt_sock);
		return NULL;  
	}
	send(clnt_sock,recv_buf,recv_len,0);
	
	close(clnt_sock);
	return NULL;
}
//-----------------------------------------------
int main(int argc,char *argv[])
{
	int srv_sock;
	socklen_t clnt_sock;
	socklen_t clnt_addr_size;
	struct sockaddr_in srv_addr;
	struct sockaddr_in clnt_addr;

	srv_sock = socket(AF_INET,SOCK_STREAM,0);
	if(srv_sock<0) {
		cout << "socket() error" << endl;
		exit(-1);
	}

	memset(&srv_addr,0,sizeof(srv_addr));
	srv_addr.sin_family = AF_INET;
	srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	srv_addr.sin_port = htons(atoi(SRV_PORT));

	if(bind(srv_sock,(struct sockaddr *)&srv_addr,sizeof(srv_addr))<0) {
		cout << "bind() error" << endl;
		close(srv_sock);
		exit(-1);
	}

	if(listen(srv_sock,WAIT_QUEUE)<0) {
		cout << "listen() error" << endl;
		close(srv_sock);
		exit(-1);
	}

	while(1) {
		clnt_addr_size = sizeof(clnt_addr);
		clnt_sock = accept(srv_sock,(struct sockaddr *)&clnt_addr,&clnt_addr_size);
		if(clnt_sock<0) {
			cout << "accept() error" << endl;
			close(srv_sock);
			exit(-1);
		}

		pthread_t tid;
		
		// create a thread to deal with a client
		pthread_create(&tid,NULL,clnt_proc,(void *)clnt_sock);
	}

	close(srv_sock);
	return 0;
}
//------------------------------------------------
